package com.hfut.eeg.common.eegParse;

import com.hfut.eeg.common.util.EEGUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;

/**
 * @author 梁琦
 * @program: eeg
 * @Package com.hfut.eeg.common.eegParse
 * @Description: 负责EEG数据解析的核心类
 * @date 2019-11-19 17:14
 */
//使用NIO方式读取文件
public class EEGDataParse {
    private static final Logger LOGGER = LoggerFactory.getLogger(EEGDataParse.class);

    private NkEEG nkEEG = new NkEEG();

    private Hdr hdr = new Hdr();

    //文件指针的位置
    private int point = 0;

    public Hdr needhdr(String fileName){
        nkEEG.setFile(EEGUtil.transformFileName(fileName));
        nkEEG.setFileName(fileName);
        try(RandomAccessFile aFile = new RandomAccessFile(fileName,"r");
            FileChannel fileChannel = aFile.getChannel()) {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int extendPos;
            if(fileChannel.read(buffer) != -1){
                Double[] H1,H2 ;
                buffer.flip();
                //get引起文件指针的移动
                H1 = EEGUtil.readUnsignedBytes(aFile,128);
                //处理完需要对文件指针进行重新定位
                point+=128;
                aFile.seek(point);
                H2 = EEGUtil.readUnsignedBytes(aFile,896);
                point+=896;
                aFile.seek(point);

                extendPos = (int) (H2[880-1]*256+H2[879-1]);
                //重新定位
                if(extendPos>0){
                    nkEEG.setExtended(1);
                }else {
                    nkEEG.setExtended(0);
                }

                //指定下一次光标的位置
                //matlab下标计算是从1开始的
                int EEG2Pos = (int) (H2[21]*256*256*256+H2[20]*256*256+H2[19]*256+H2[18]);
                aFile.seek(EEG2Pos);

                //计算DATAPos开始位置，用于读取.eeg文件信息
                int DATAPos = 0;
                if(nkEEG.getExtended()==1){
                    System.out.println("nkEEG.getExtended()==1");
                }else {
                    Double[] H3;
                    H3 = EEGUtil.readUnsignedBytes(aFile,38);
                    DATAPos = (int) (H3[21]*256*256*256+H3[20]*256*256+H3[19]*256+H3[18]);
                }

                //把之前的信息泄露出去
                aFile.seek(DATAPos+20);
                point+=DATAPos+20;

                if(nkEEG.getExtended() == 1){
                    System.out.println("-----nkEEG.getExtended() == 1");
                }else {
                    Integer []tmp = EEGUtil.readUcharBytes(aFile,6) ;
                    nkEEG.setTo(tmp);
                    point += 6;

                    //500
                    //计算数据刷新频率
                    Integer[] tag = EEGUtil.readShortBytes(aFile,1);
                    nkEEG.setSamplingFreq(getSamplingFreq(tag[0].intValue()));

                    //计算数据总共组数
                    Long[] t1 = EEGUtil.readUint32Bytes(aFile,1);
                    nkEEG.setSampleNum(nkEEG.getSamplingFreq()*t1[0]/10);
                    //32768
                    //计算数据偏移位置
                    nkEEG.setOffset(EEGUtil.readShortBytes(aFile,1)[0].intValue());
                    //0.0977
                    nkEEG.setCal((50/(double)EEGUtil.readShortBytes(aFile,1)[0]));

                    Integer []t2 = EEGUtil.readUcharBytes(aFile,2) ;
                    int reserveSize = 0;
                    //计算通道数量
                    nkEEG.setChNum(EEGUtil.readUcharBytes(aFile,1)[0]+1);
                    //表示.2E文件的名字
                    String ELFILENAME = nkEEG.getFile().getPath()+"\\"+ nkEEG.getFile().getName()+".21E";

                    for (int i=1;i<=nkEEG.getChNum()-1;i++){
                        Integer[] t3 = EEGUtil.readUcharBytes(aFile,8);
                        Integer t4 = t3[0];
                        String chanStr = String.format("%04d",t4)+"=";
                        ArrayList a= readIni(ELFILENAME,chanStr,"%s");
                        nkEEG.getLabel().addAll(readIni(ELFILENAME,chanStr,"%s"));
                        nkEEG.setLabel(nkEEG.getLabel());
                        nkEEG.getElectrodeCode().add(Double.valueOf(t4));
                        nkEEG.setElectrodeCode(nkEEG.getElectrodeCode());
                        Integer[] t5 = EEGUtil.readUcharBytes(aFile,2);
                    }
                    nkEEG.getLabel().add("DM");
                    nkEEG.setLabel(nkEEG.getLabel());
                    nkEEG.getElectrodeCode().add((double) 9999);
                    nkEEG.setElectrodeCode(nkEEG.getElectrodeCode());
                    nkEEG.setWavePos(DATAPos+ 20 + 12 + 7 + 10 *(nkEEG.getChNum()-1));
                    //System.out.println("");
                }
                nkEEG.setCalDC((double)(500*1000/(float)1365));

                //设置Hdr对象值
                hdr.setFs(nkEEG.getSamplingFreq());
                hdr.setnChans(nkEEG.getChNum());
                hdr.setLabel(nkEEG.getLabel());
                hdr.setnSamples(nkEEG.getSampleNum());
                hdr.setnSamplesPre(0);
                hdr.setnTrials(1);
                hdr.setOrig(nkEEG);

            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return hdr;
    }

    /**
    * @Description: 获取EEG数据
    * @param hdr 表示hdr对象，其中含有所有可能需要用到的信息，包括刷新频率等等
     * @param begsample EEG数据开始的组数
     * @param endsample EEG数据结束的组数
    * @return ArrayList<ArrayList>表示存储着endsample-begsample个组的EEG信息
    * @author 梁琦
    * @date 2019-11-21 16:40
    * @throws
    */
    public ArrayList<ArrayList> needDat(Hdr hdr, Long begsample, Long endsample){
        NkEEG origHdr = hdr.getOrig();
        int nchan = origHdr.getChNum();
        double calEEG = origHdr.getCal();
        double calDC = origHdr.getCalDC();
        int zeroLevel = origHdr.getOffset();
        ArrayList eleCode = origHdr.getElectrodeCode();

        long offset = origHdr.getWavePos()+(begsample-1)*nchan*2;
        long nsample = endsample-begsample+1;
        long blocksize = nsample*nchan;

        Integer[] buf = readLowLevel(origHdr.getFileName(),offset,blocksize);
        ArrayList<ArrayList> dat = EEGUtil.reShape(buf,nchan,zeroLevel,eleCode,calEEG,calDC);
        //System.out.println(dat);
        return dat;
    }

    public Integer[] readLowLevel(String fileName, long offset, long numwords){
        Integer[] dat = null;
        try(RandomAccessFile aFile = new RandomAccessFile(fileName,"r")) {
            aFile.seek(offset);
            dat=EEGUtil.readShortBytes(aFile, (int) numwords);
            return dat;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dat;
    }



    /**
    * @Description: 获取数据刷新频率
    * @param in 字节表示的数字，用于解析频率
    * @return Integer 数据刷新频率
    * @author 梁琦
    * @date 2019-12-30 19:48
    * @throws
    */
    public Integer getSamplingFreq(Integer in){
        Integer result = null;
        if(in == 49252){
            result = 100;
        }else if(in == 49352){
            result = 200;
        }else if(in == 49652){
            result = 500;
        }else if(in == 50152){
            result = 1000;
        }else if(in == 51152){
            result = 2000;
        }else if(in == 54152){
            result = 5000;
        }
        else if(in == 59152){
            result = 10000;
        }
        return result;
    }

    public long getPointIndex(RandomAccessFile file){
        try {
            return file.getFilePointer()/8;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return -1;
    }


    /**
    * 解析.21E标签部分
    */
    public ArrayList<String> readIni(String fileName,String ele,String format) throws InterruptedException {
        //String []result = null;
        ArrayList<String> list = new ArrayList<>();
        String data = null;
        int number = 1;
        if(!"%s".equals(format)){
            number = Integer.MAX_VALUE;
        }
        String token = "";
        try(RandomAccessFile file = new RandomAccessFile(fileName,"rw")){
            ele = ele.trim().toLowerCase();
            String line ,lowerLine;
            while ((line=file.readLine())!=null){
                //小端读取
                lowerLine = line.trim().toLowerCase();
                if(lowerLine.contains(ele)){
                    data = line.substring(ele.length());
                    break;
                }
            }

            if("%s".equals(format)){
                String val;
                if(number==1){
                    val = EEGUtil.detoken(data.trim(),token);
                    if (val.indexOf(0)=='='){
                        val = val.substring(1);
                    }
                    list.add(val);
                    return list;
                }
                //下面这些在debug时也没有使用到
                list.add(EEGUtil.detoken(data.trim(),token));
                int count =1;
                while (count<number){
                    line = file.readLine();
                    if(line==null){
                        return list;
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.warn(fileName+"正在被使用");
            Thread.sleep(100);
            readIni(fileName, ele, format);
        }
        return list;
    }



    public static void main(String[] args) {
        long startTime=System.currentTimeMillis();
        EEGDataParse parse = new EEGDataParse();
        Hdr hdr = parse.needhdr("D:\\毕设\\数据\\脑电数据\\DA11000W.EEG");
        int ptime =20,chn=4;

        ArrayList<ArrayList> lists =parse.needDat(hdr, (long) 573,hdr.getnSamples());
        long endTime=System.currentTimeMillis();
        System.out.println("程序运行时间: "+(endTime-startTime));
        //new EEGDataParse().needhdr("D:\\毕设\\数据\\脑电数据\\DA11000W.EEG");
        //new EEGDataParse().readIni("D:\\毕设\\数据\\脑电数据\\DA11000W.21E","0000=","%s");
    }
}
